﻿using Mozi.HttpEmbedded.Extension;
using System;
using System.Collections.Generic;

namespace Mozi.Live.RTP
{
    /// <summary>
    /// RTP数据包
    /// </summary>
    public class RTPPackage
    {
        private RTPExtension _extInfo;

        /// <summary>
        /// 版本 2bits
        /// </summary>
        public byte Version { get; set; }
        /// <summary>
        /// 是否含有末尾填充 1bit
        /// </summary>
        public bool Padding { get; set; }
        /// <summary>
        /// 是否含有扩展头信息 1bit
        /// </summary>
        public bool Extension { get; set; }
        /// <summary>
        /// 贡献来源标识符数量 4bits
        /// </summary>
        public byte CSRCcount { get { return (byte)(CSRCList != null ? (CSRCList.Count > 15 ? 15 : CSRCList.Count) : 0); } }
        /// <summary>
        /// 帧分割符 1bit
        /// </summary>
        public bool Marker { get; set; }
        /// <summary>
        /// 荷载类型 7bits
        /// </summary>
        public byte PayloadType { get; set; }
        /// <summary>
        /// 包序号 16bits
        /// </summary>
        public ushort SequenceNumber { get; set; }
        /// <summary>
        /// 采样包的开始时间戳 32bits
        /// </summary>
        public uint Timestamp { get; set; }
        /// <summary>
        /// 同步源编号 32bits
        /// </summary>
        public uint SSRC { get; set; }
        /// <summary>
        /// 贡献源标识符 每项32bits 最多 15项
        /// </summary>
        public List<int> CSRCList { get; set; }
        /// <summary>
        /// 扩展属性
        /// </summary>
        public RTPExtension ExtInfo
        {
            get { return _extInfo; }
            set
            {
                _extInfo = value;
                Extension = true;
            }
        }
        /// <summary>
        /// 荷载部分
        /// </summary>
        public byte[] Payload { get; set; }

        /// <summary>
        /// 字节数测算
        /// </summary>
        public int Length
        {
            get
            {
                return 4 + 4 + 4 * CSRCcount+(Payload!=null?Payload.Length:0)+(ExtInfo!=null?ExtInfo.ByteCount:0);
            }
        }
        /// <summary>
        /// 实例化
        /// </summary>
        public RTPPackage()
        {
            //版本
            Version = 2;
        }
        /// <summary>
        /// 打包数据
        /// </summary>
        /// <returns></returns>
        public byte[] Pack()
        {
            List<byte> arrData = new List<byte>();
            arrData.Add((byte)(Version << 6 | (Padding ? 0b00100000 : 0x00) | (Extension ? 0b00010000 : 0x00) | CSRCcount));
            arrData.Add((byte)((Marker ? 0b10000000 : 0b00000000) | PayloadType));
            arrData.AddRange(SequenceNumber.ToBigEndian());
            arrData.AddRange(Timestamp.ToBigEndian());
            arrData.AddRange(SSRC.ToBigEndian());
            for (int i = 0; i < CSRCcount; i++)
            {
                int item = CSRCList[i];
                arrData.AddRange(item.ToBigEndian());
            }
            if (Extension)
            {
                arrData.AddRange(ExtInfo.Pack());
            }
            if (Payload != null)
            {
                arrData.AddRange(Payload);
            }
            //TODO padding
            return arrData.ToArray();
        }
        /// <summary>
        /// 解析数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static RTPPackage Parse(byte[] data)
        {
            RTPPackage pack = new RTPPackage();
            byte header = data[0];
            byte follow = data[1];
            pack.Version = (byte)(header >> 6);
            pack.Padding = ((header & 0b00100000) >> 5) == 1;
            pack.Extension = ((header & 0b00010000) >> 4) == 1;

            byte csrcCount = (byte)(header & 0b00001111);
            pack.Marker = follow >> 7 == 1;
            pack.PayloadType = (byte)(follow & 0b01111111);

            pack.SequenceNumber = data.GetBigEndianUInt16(2);
            pack.Timestamp = data.GetBigEndianUInt32(4);
            pack.SSRC = data.GetBigEndianUInt32(8);
            pack.CSRCList = new List<int>();
            for (int i = 0; i < csrcCount; i++)
            {
                var arrItem = new byte[4];
                Array.Copy(data, 12 + i * 4, arrItem, 0, 4);
            }
            //extension
            if (pack.Extension)
            {
                pack.ExtInfo = new RTPExtension();
                pack.ExtInfo.Profile = data.GetBigEndianUInt16(12 + csrcCount * 4);
                pack.ExtInfo.Length = data.GetBigEndianUInt16(12 + csrcCount * 4 + 2);
                byte[] arrExt = new byte[pack.ExtInfo.Length];
                Array.Copy(data, 12 + csrcCount + 4, arrExt, 0, arrExt.Length);
                pack.ExtInfo.Extension = arrExt;
            }
            //计算扩展偏移值
            int offset = pack.Extension ? (4 + pack.ExtInfo.Extension.Length):0;
            //payload
            byte paddingCount = pack.Padding ? data[data.Length - 1] : (byte)0;
            pack.Payload = new byte[data.Length - 12 - csrcCount * 4 -offset- (paddingCount > 0 ? paddingCount + 1 : 0)];
            //padding
            Array.Copy(data, 12 + csrcCount * 4+offset, pack.Payload, 0, pack.Payload.Length);
            return pack;
        }
    }
    /// <summary>
    /// RTP头扩展
    /// </summary>
    public class RTPExtension
    {
        private byte[] extension;

        /// <summary>
        /// 扩展标识 16bits
        /// </summary>
        public ushort Profile { get; set; }
        /// <summary>
        /// 值长度 16bits
        /// </summary>
        public ushort Length { get; set; }
        /// <summary>
        /// 值
        /// </summary>
        public byte[] Extension
        {
            get { return extension; }
            set
            {
                extension = value;
                Length = (ushort)extension.Length;
            }
        }
        /// <summary>
        /// 字节数测算
        /// </summary>
        public int ByteCount
        {
            get
            {
                return 2 + 2 + (Extension != null ? Extension.Length : 0);
            }
        }
        /// <summary>
        /// 打包数据
        /// </summary>
        /// <returns></returns>
        public byte[] Pack()
        {
            List<byte> arrData = new List<byte>();
            arrData.AddRange(Profile.ToBigEndian());
            arrData.AddRange(Length.ToBigEndian());
            arrData.AddRange(Extension);
            return arrData.ToArray();
        }
    }
}
